package com.xw.unification.interfaces;

import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * API 版本号比较器
 *
 * @author qiwei
 * @date 2023-8-10 16:00:00
 * @since v1.0.0
 */
public interface ApiVersionComparator extends Comparator<String> {

    /**
     * 版本号字符串比较
     * <p>
     *     version1 > version2, 返回  1;
     *     version1 < version2, 返回 -1;
     *     version1 = version2, 返回  0;
     * </p>
     *
     *
     * @param version1 the first object to be compared.
     * @param version2 the second object to be compared.
     * @return int
     */
    @Override
    default int compare(String version1, String version2) {
        version1 = trim(version1);
        version2 = trim(version2);
        if (Objects.equals(version1, version2)) {
            return 0;
        } else if (version1 == null) {
            return 1;
        } else if (version2 == null) {
            return -1;
        }
        return version1.compareTo(version2);
    }

    /**
     * 版本号数值比较
     * <p>
     *     version1 > version2, 返回  1;
     *     version1 < version2, 返回 -1;
     *     version1 = version2, 返回  0;
     * </p>
     *
     * @param version1 the first object to be compared.
     * @param version2 the second object to be compared.
     * @return int
     */
    default int compareOnlyDigit(String version1, String version2) {
        List<Integer> version1IntegerList = remainDigit(version1);
        List<Integer> version2IntegerList = remainDigit(version2);
        int length1 = version1IntegerList.size();
        int length2 = version2IntegerList.size();
        if (length1 == 0 && length2 == 0) {
            return 0;
        }
        int maxLength = Math.max(length1, length2);
        int compare;
        for (int i = 0; i < maxLength; i ++) {
            if (i > length1 - 1) {
                for (int j = i; j < maxLength; j++) {
                    if (!version2IntegerList.get(j).equals(0)) {
                        return -1;
                    }
                }
                return 0;
            } else if (i > length2 - 1) {
                for (int j = i; j < maxLength; j++) {
                    if (!version1IntegerList.get(j).equals(0)) {
                        return 1;
                    }
                }
                return 0;
            }
            try {
                compare = version1IntegerList.get(i) - version2IntegerList.get(i);
                if (compare != 0) {
                    return compare > 0 ? 1 : -1;
                }
            } catch (Exception e) {
                // swallow the exception
            }
        }
        return 0;
    }

    /**
     * 版本号数值比较, 含精度比较
     * <p>
     *     version1 > version2, 返回  1;
     *     version1 < version2, 返回 -1;
     *     version1 = version2, 返回  0;
     * </p>
     *
     * @param version1 the first object to be compared.
     * @param version2 the second object to be compared.
     * @return int
     */
    default int compareOnlyDigitWithPrecision(String version1, String version2) {
        List<Integer> version1IntegerList = remainDigit(version1);
        List<Integer> version2IntegerList = remainDigit(version2);
        int length1 = version1IntegerList.size();
        int length2 = version2IntegerList.size();
        if (length1 == 0 && length2 == 0) {
            return 0;
        }
        int maxLength = Math.max(length1, length2);
        int compare;
        for (int i = 0; i < maxLength; i ++) {
            if (i > length1 - 1) {
                return -1;
            } else if (i > length2 - 1) {
                return 1;
            }
            try {
                compare = version1IntegerList.get(i) - version2IntegerList.get(i);
                if (compare != 0) {
                    return compare > 0 ? 1 : -1;
                }
            } catch (Exception e) {
                // swallow the exception
            }
        }
        return 0;
    }

    /**
     * 版本号数值比较, 含精度比较
     * <p>
     *     version1 > version2, 返回  1;
     *     version1 < version2, 返回 -1;
     *     version1 = version2, 返回  0;
     * </p>
     *
     * @param version1 the first object to be compared.
     * @param version2 the second object to be compared.
     * @return int
     */
    default int compareOnlyDigit(String version1, String version2, boolean ignorePrecision) {
        // 排除所有为 null 的情况
        if (Objects.equals(version1, version2)) {
            return 0;
        } else if (version1 == null) {
            return -1;
        } else if (version2 == null) {
            return 1;
        }
        int index1 = 0;
        int index2 = 0;
        int compare;
        NextInteger nextInteger1, nextInteger2;
        Integer value1, value2;
        while (index1 <= version1.length() && index2 <= version2.length()) {
            nextInteger1 = getNextInteger(version1, index1);
            nextInteger2 = getNextInteger(version2, index2);
            value1 = nextInteger1.getNow();
            value2 = nextInteger2.getNow();
            // 排除为 null 的情况
            if (value1 == null && value2 == null) {
                return 0;
            } else if (value1 != null && value2 != null) {
                compare = value1.compareTo(value2);
                if (compare != 0) {
                    return compare;
                }
            } else if (!ignorePrecision) {
                if (value1 == null) {
                    return -1;
                } else {
                    return 1;
                }
            } else {
                if (value1 != null && !value1.equals(0)) {
                    return 1;
                } else if (value2 != null && !value2.equals(0)) {
                    return -1;
                }
            }
            index1 = nextInteger1.getNextStartIndex();
            index2 = nextInteger2.getNextStartIndex();
        }
        return 0;
    }

    /**
     * 字符串截去 blank
     *
     * @param string    字符串
     * @return String
     */
    default String trim(String string) {
        return string == null ? null : string.trim();
    }

    /**
     * 字符串只保留数值
     *
     * @param string    带有数字的字符串
     * @return List
     */
    default List<Integer> remainDigit(String string) {
        List<StringBuilder> builderList = new ArrayList<>();
        StringBuilder builder = new StringBuilder();
        if (string == null) {
            return new ArrayList<>();
        }
        char ch;
        for (int i = 0; i < string.length(); i++) {
            ch = string.charAt(i);
            if (ch >= '0' && ch <= '9') {
                builder.append(ch);
            } else if (builder.length() > 0) {
                builderList.add(builder);
                builder = new StringBuilder();
            }
        }
        if (builder.length() > 0) {
            builderList.add(builder);
        }
        return builderList.stream()
                .map(build -> {
                    try {
                        return (build == null || build.length() == 0) ?
                                0 : Integer.parseInt(build.toString());
                    } catch (Exception e) {
                        return 0;
                    }
                }).collect(Collectors.toList());
    }

    default NextInteger getNextInteger(String string, int startIndex) {
        if (string == null || startIndex < 0 || startIndex >= string.length()) {
            return new NextInteger(null, -1);
        }
        StringBuilder builder = new StringBuilder();
        char ch;
        while (startIndex < string.length() ) {
            ch = string.charAt(startIndex);
            if (ch >= '0' && ch <= '9') {
                builder.append(ch);
            } else if (builder.length() > 0) {
                try {
                    return new NextInteger(Integer.parseInt(builder.toString()), startIndex >= string.length() ? -1 : startIndex);
                } catch (Exception e) {
                    return new NextInteger(null, startIndex >= string.length() ? -1 : startIndex);
                }
            }
            startIndex++;
        }
        if (builder.length() > 0) {
            try {
                return new NextInteger(Integer.parseInt(builder.toString()), -1);
            } catch (Exception e) {
                return new NextInteger(null, -1);
            }
        } else {
            return new NextInteger(null, -1);
        }
    }

    @Getter
    class NextInteger {
        private Integer now;
        private int nextStartIndex;

        public NextInteger(Integer now, int nextStartIndex) {
            this.now = now;
            this.nextStartIndex = nextStartIndex;
        }
    }
}
